using System;
using System.Collections.Generic;
using System.Text;
using Sandia.MVCFramework.Request;

namespace Sandia.MVCFramework.Request
{
    /// <summary>
    /// A generic that creates requests that takes two parameters
    /// </summary>
    /// <remarks>
    /// This generic simplifies the creation both of the request and the underlying parameter types.
    /// It uses the ObjectParameter to create those types.  So you simply have to specify the object
    /// types that get stored as parameters and (if desired) expose the accessors using semantically
    /// meaningful names.
    /// </remarks>
    /// <typeparam name="T">The first type to be stored as a parameter</typeparam>
    /// <typeparam name="R">The second type to be stored as a parameter</typeparam>
    /// <typeparam name="S">The third type to be stored as a parameter</typeparam>
    /// <typeparam name="U">The fourth type to be stored as a parameter</typeparam>
    public class FourParameterRequest<T, R, S, U>: AbstractStandardRequest
    {
        private string[] paramNames = new string[] {
            "p1",
            "p2",
            "p3",
            "p4"
        };
        

        /// <summary>
        /// Create a new request
        /// </summary>
        /// <param name="p1">The first object to be stored as a parameter</param>
        /// <param name="p2">the second object to be stored as a parameter</param>
        /// <param name="p3">The third object to be stored as a parameter</param>
        /// <param name="p4">The fourth object to be stored as a parameter</param>
        public FourParameterRequest(T p1, R p2, S p3, U p4)
        {

            parameters[paramNames[0]] = new ObjectParameter<T>(p1);
            parameters[paramNames[1]] = new ObjectParameter<R>(p2);
            parameters[paramNames[2]] = new ObjectParameter<S>(p3);
            parameters[paramNames[3]] = new ObjectParameter<U>(p4);
        }

        /// <summary>
        /// Create a new request
        /// </summary>
        /// <param name="p1">The first object to be stored as a parameter</param>
        /// <param name="p1Name">The name of the first parameter</param>
        /// <param name="p2">The second object to be stored as a parameter</param>
        /// <param name="p2Name">The name of the second parameter</param>
        /// <param name="p3">The third object to be stored as a parameter</param>
        /// <param name="p3Name">The name of the third parameter</param>
        /// <param name="p4">The fourth object to be stored as a parameter</param>
        /// <param name="p4Name">The name of the fourth parameter</param>
        public FourParameterRequest(T p1, string p1Name, R p2, string p2Name, S p3, string p3Name, U p4, string p4Name)
        {
            paramNames[0] = p1Name;
            paramNames[1] = p2Name;
            paramNames[2] = p3Name;
            paramNames[3] = p4Name;

            parameters[paramNames[0]] = new ObjectParameter<T>(p1);
            parameters[paramNames[1]] = new ObjectParameter<R>(p2);
            parameters[paramNames[2]] = new ObjectParameter<S>(p3);
            parameters[paramNames[3]] = new ObjectParameter<U>(p4);
        }

        /// <summary>
        /// Accessor for the first type
        /// </summary>
        /// <remarks>
        /// Expose publicly in a subclass using a semantically meaningful name.
        /// </remarks>
        protected T Param1
        {
            get { return (T)parameters[paramNames[0]].Data; }
            set { parameters[paramNames[0]] = new ObjectParameter<T>(value); }
        }

        /// <summary>
        /// Accessor for the second type
        /// </summary>
        /// <remarks>
        /// Expose publicly in a subclass using a semantically meaningful name.
        /// </remarks>
        protected R Param2
        {
            get { return (R)parameters[paramNames[1]].Data; }
            set { parameters[paramNames[1]] = new ObjectParameter<R>(value); }
        }

        /// <summary>
        /// Accessor for the third type
        /// </summary>
        /// <remarks>
        /// Explicitly expose in a subclass using a semantically meaningful name.
        /// </remarks>
        protected S Param3
        {
            get { return (S)parameters[paramNames[2]].Data; }
            set { parameters[paramNames[2]] = new ObjectParameter<S>(value); }
        }

        /// <summary>
        /// Accessor for the fourth type
        /// </summary>
        /// <remarks>
        /// Explicitly expose in a subclass using a semantically meaningful name.
        /// </remarks>
        protected U Param4
        {
            get { return (U)parameters[paramNames[3]].Data; }
            set { parameters[paramNames[3]] = new ObjectParameter<U>(value); }
        }

        /// <summary>
        /// Initialize both parameters to null
        /// </summary>
        protected override void initParameters()
        {
            parameters[paramNames[0]] = null;
            parameters[paramNames[1]] = null;
            parameters[paramNames[2]] = null;
            parameters[paramNames[3]] = null;
        }
    }
}
